package org.jflame.web.spring.inteceptor;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jflame.commons.util.ArrayHelper;
import org.springframework.format.datetime.standard.DateTimeContext;
import org.springframework.format.datetime.standard.DateTimeContextHolder;
import org.springframework.util.ObjectUtils;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.i18n.AbstractLocaleContextResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.support.RequestContextUtils;

import java.time.DateTimeException;
import java.time.ZoneId;
import java.util.TimeZone;

public class LocaleAndTimeZoneChangeInterceptor extends LocaleChangeInterceptor {

    public static final String DEFAULT_TIMEZONE_PARAM_NAME = "time-zone";

    private String timeZoneParamName = DEFAULT_TIMEZONE_PARAM_NAME;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws ServletException {
        String newZone = request.getParameter(getTimeZoneParamName());
        String newLocale = request.getParameter(getParamName());
        if (checkHttpMethod(request.getMethod())) {
            LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
            if (localeResolver == null) {
                throw new IllegalStateException("No LocaleResolver found: not in a DispatcherServlet request?");
            }
            if (newLocale != null) {
                try {
                    localeResolver.setLocale(request, response, parseLocaleValue(newLocale));
                } catch (IllegalArgumentException ex) {
                    if (isIgnoreInvalidLocale()) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Ignoring invalid locale value [" + newLocale + "]: " + ex.getMessage());
                        }
                    } else {
                        throw ex;
                    }
                }
            }
            if (newZone != null) {
                if (localeResolver instanceof AbstractLocaleContextResolver) {
                    AbstractLocaleContextResolver localeContext = ((AbstractLocaleContextResolver) localeResolver);
                    try {
                        ZoneId zoneId = ZoneId.of(newZone);// TimeZone.getTimeZone如果给定id是错误的将返回GMT0,
                        // 无法判断参数是否正确所以用ZoneId转下
                        if (zoneId != null) {
                            localeContext.setDefaultTimeZone(TimeZone.getTimeZone(zoneId));
                            DateTimeContext dtCxt = new DateTimeContext();
                            dtCxt.setTimeZone(zoneId);
                            DateTimeContextHolder.setDateTimeContext(dtCxt);
                        } else {
                            throw new DateTimeException("invalid TimeZone value [" + newZone + "]");
                        }
                    } catch (DateTimeException ex) {
                        if (isIgnoreInvalidLocale()) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("Ignoring invalid TimeZone value [" + newZone + "]: " + ex.getMessage());
                            }
                        } else {
                            throw ex;
                        }
                    }
                }
            }

        }
        return true;
    }

    protected boolean checkHttpMethod(String currentMethod) {
        String[] configuredMethods = getHttpMethods();
        if (ObjectUtils.isEmpty(configuredMethods)) {
            return true;
        }
        return ArrayHelper.containIgnoreCase(configuredMethods, currentMethod);
    }

    public String getTimeZoneParamName() {
        return timeZoneParamName;
    }

    public void setTimeZoneParamName(String timeZoneParamName) {
        this.timeZoneParamName = timeZoneParamName;
    }

}
